#include "NetWorkProDefine.h"
#include <sys/fcntl.h>

extern int h_errno;

char const* getfamilystr(short type)
{
    static char str[32] = {0};
    switch (type)
    {
    case AF_INET:
        strcpy(str, "internetwork");
        break;
    default:
        memset(str, 0, sizeof(0));
        break;
    }
    return str;
}


void display_sockaddrin(struct sockaddr_in* saddrin)
{
    if (NULL != saddrin)
    {
        printf("addr ip :%s\tport :%u\tfamily :%s\n", inet_ntoa(saddrin->sin_addr), ntohs(saddrin->sin_port), getfamilystr(saddrin->sin_family));
    }
}


void display_sockaddr(struct sockaddr* saddr)
{
    if (NULL != saddr)
    {
        struct sockaddr_in* saddrin = (struct sockaddr_in*)saddr;
        display_sockaddrin(saddrin);
    }
}

int udp_client(const char *host, const char *serv, void **saptr, socklen_t *lenp)
{
	int sockfd;
	int n;
	struct addrinfo hints, *res, *ressave;
	
    /* 确定套接字属性 */
	bzero(&hints, sizeof(hints));
	hints.ai_family = AF_UNSPEC;//通用协议族，IPV4、IPV6都可
	hints.ai_socktype = SOCK_DGRAM;	
	
	if ((n = getaddrinfo(host, serv, &hints, &res)) != 0) {
		printf("udp_client error for %s, %s:%s\n", host, serv, gai_strerror(n));
		return -1;
	}
	ressave = res;

    /* 创建UDP套接字 */
	do {
		sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
		if (sockfd >= 0) break;
	} while ((res = res->ai_next) != NULL);
 
	if (res == NULL) {
		printf("udp_client error for %s, %s\n", host, serv);
		return -1;
	}
 
	*saptr = malloc(res->ai_addrlen);
	memcpy(*saptr, res->ai_addr, sizeof(res->ai_addrlen));
	*lenp = res->ai_addrlen;
 
	freeaddrinfo(ressave);
	return sockfd;
}

void pr_cpu_time(void)
{
    double user, sys;
    struct rusage myusage, childusage;

    if (getrusage(RUSAGE_SELF, &myusage) < 0)
    {
        printf("getrusage error\n");
        return ;
    }
    if (getrusage(RUSAGE_CHILDREN, &childusage) < 0)
    {
        printf("getrusage of children error\n");
        return ;
    }

    user = (double) myusage.ru_utime.tv_sec + myusage.ru_utime.tv_usec / 1000000.0;
    user += (double) childusage.ru_utime.tv_sec + childusage.ru_utime.tv_usec / 1000000.0;
    sys = (double) myusage.ru_stime.tv_sec + myusage.ru_stime.tv_usec / 1000000.0;
    sys += (double) childusage.ru_stime.tv_sec + childusage.ru_stime.tv_usec / 1000000.0;
    printf("user time :%g, sys time :%g\n", user, sys);
}


int tcp_listen(char* ip, char* port, socklen_t* addrlen)
{
    if (NULL == addrlen)
    {
        printf("addrlen is null.\n");
        return -1;
    }
    
    struct sockaddr_in servaddr;
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    if (NULL != ip)
    {
        inet_pton(AF_INET, ip, &servaddr.sin_addr);
    }
    else
    {
        servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
    }
	if (NULL != port)
	{
		servaddr.sin_port = htons(atoi(port));
	}
	else
	{
		servaddr.sin_port = htons(SERV_PORT);
	}
	
    
    
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if(bind(listenfd, (SA*)&servaddr, sizeof(servaddr)) == 0
        && listen(listenfd, LISTENENQ) == 0)
    {
        *addrlen = sizeof(servaddr);
        return listenfd;
    }
    else
    {
        printf("bind or listen error, code :%u\tmsg :%s\n", errno, strerror(errno));
        printf("ip :%u\tport :%s\n", servaddr.sin_addr.s_addr, port);
    }

    return -1;
}


void gethostbyaddrs(int argc, char** argv)
{
    char * ptr, **pptr;
    char str[INET_ADDRSTRLEN];
    struct hostent *hptr;
    struct in_addr* addr;
    struct sockaddr_in saddr;

    while (--argc > 0)
    {
        ptr = *++argv;
        if(!inet_aton(ptr, &saddr.sin_addr))
        {
            printf("inet_aton error\n");
            return ;
        }

        if((hptr = gethostbyaddr((void*)&saddr.sin_addr, 4, AF_INET)) == NULL )
        {
            printf("gethostbyaddr error for addr :%s\n", ptr);
            return ;
        }

        printf("official hostname :%s\n", hptr->h_name);
        for ( pptr = hptr->h_aliases; *pptr != NULL; pptr++)
        {
            printf("\talias :%s\n", *pptr);
        }
        switch (hptr->h_addrtype)
        {
        case AF_INET:
            pptr = hptr->h_addr_list;
            for(;*pptr != NULL;pptr++)
            {
                printf("\taddress :%s\n", inet_ntop(hptr->h_addrtype, *pptr, str, sizeof(str)));
            }
            break;
        default:
            printf("unknown address type\n");
            break;
        }
    }
}



void gethostbynames(int argc, char** argv)
{
    if (argc != 2)
    {
        printf("usage: %s www.google.com\n", *argv);
        return ;
    }

    char *name = argv[1];
    struct hostent * hptr;
    hptr = gethostbyname(name);
    if(hptr == NULL)
    {
        printf("gethostbyname error for host :%s:%s\n", name, hstrerror(h_errno));
        return ;
    }

    printf("\tofficial: %s\n", hptr->h_name);

    char **pptr;
    char str[INET_ADDRSTRLEN];
    for (pptr = hptr->h_aliases; *pptr != NULL; pptr++)
    {
        printf("\ttalias: %s\n", *pptr);
    }

    switch (hptr->h_addrtype)
    {
    case AF_INET:
        pptr = hptr->h_addr_list;
        for(; *pptr != NULL; pptr++)
        {
            printf("\taddress: %s\n", inet_ntop(hptr->h_addrtype, hptr->h_addr, str, sizeof(str)));
        }
        break;
    default:
        printf("unknown address type\n");
        break;
    }
}



struct addrinfo* host_serv(const char *hostname, const char *service, int family, int socktype)
{
    int n;
    struct addrinfo hints, *res;
    bzero(&hints, sizeof(hints));
    hints.ai_flags = AI_CANONNAME;
    hints.ai_family = family;
    hints.ai_socktype = socktype;

    if ((n = getaddrinfo(hostname, service, &hints, &res) !=0 ))
    {
        printf("getaddrinfo error :%s\n", gai_strerror(n));
        return NULL;
    }
    return res;
}


char const* sock_ntop(const struct sockaddr *sa, socklen_t salen)
{
    char		portstr[8];
    static char str[128];		/* Unix domain is largest */
 
	switch (sa->sa_family) 
    {
	case AF_INET: {
		struct sockaddr_in	*sin = (struct sockaddr_in *) sa;
 
		if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == NULL)
			return(NULL);
		if (ntohs(sin->sin_port) != 0) 
        {
			snprintf(portstr, sizeof(portstr), ":%d", ntohs(sin->sin_port));
			strcat(str, portstr);
		}
		return(str);
	}
 
#ifdef	IPV6
	case AF_INET6: 
    {
		struct sockaddr_in6	*sin6 = (struct sockaddr_in6 *) sa;
 
		str[0] = '[';
		if (inet_ntop(AF_INET6, &sin6->sin6_addr, str + 1, sizeof(str) - 1) == NULL)
			return(NULL);
		if (ntohs(sin6->sin6_port) != 0) 
        {
			snprintf(portstr, sizeof(portstr), "]:%d", ntohs(sin6->sin6_port));
			strcat(str, portstr);
			return(str);
		}
		return (str + 1);
	}
#endif
    default:
        printf("unknown family type :%d\n", sa->sa_family);
    }
    return NULL;
}


int setnblock(int fd)
{
    if (fd > 0)
    {
        int flag = fcntl(fd, F_GETFL, 0);
        flag |= O_NONBLOCK;
        flag |= O_NDELAY;
        return fcntl(fd, F_SETFL, flag);
    }
    return -1;
}


int createudpsocket(int* sockfd, SA* addr, socklen_t addrlen)
{
    if (NULL == sockfd || NULL == addr || addrlen < 1)
    {
        return -1;
    }

    bzero(addr, sizeof(*addr));
    struct sockaddr_in* addr_in = (struct sockaddr_in*)addr;
    addr_in->sin_family = AF_INET;
    addr_in->sin_port = htons(SERV_PORT);
    addr_in->sin_addr.s_addr = htonl(INADDR_ANY);
    *sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    
    return 0;
}


void byteorder()
{
    union{
            short value;
            char union_bytes[sizeof(short)];
    }test;
    test.value = 0x0102;
    if(test.union_bytes[0] == 1 
                    &&test.union_bytes[1] == 2)
    {
            printf("big endian\n");
    }
    else if(test.union_bytes[0] == 2 
                    && test.union_bytes[1] == 1)
    {
            printf("little endian\n");
    }
    else
    {
            printf("unknown...\n");
    }
}


#include <net/if.h>
#include <sys/ioctl.h>
int get_local_ip(const char* ifname)
{
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == sockfd)
    {
        perror("socket error");
        return -1;
    }
    struct ifreq ifr;
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
    ifr.ifr_name[IFNAMSIZ];

    if (ioctl(sockfd, SIOCGIFADDR, &ifr) < 0)
    {
        perror("ioctl error");
        close(sockfd);
        return -1;
    }

    struct sockaddr_in sin;
    memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
    return sin.sin_addr.s_addr;
}
